/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */

#include "app_main.h"
#include "app_pwm.h"

volatile static bool int_flag = 1;

static void gpio_interrupt_handler(int32_t idx)
{
    int_flag = 0;
}

void gpio_output_test(int gpio_id, int val)
{
    gpio_pin_handle_t     handle;

    drv_pinmux_config(gpio_id, PIN_FUNC_GPIO);
    handle = csi_gpio_pin_initialize(gpio_id, NULL);
    csi_gpio_pin_config_mode(handle, GPIO_MODE_PUSH_PULL);
    csi_gpio_pin_config_direction(handle, GPIO_DIRECTION_OUTPUT);
    csi_gpio_pin_write(handle, val);
    csi_gpio_pin_uninitialize(handle);
}

void gpio_interrupt_test(int gpio_id)
{
    gpio_pin_handle_t     handle;

    drv_pinmux_config(gpio_id, PIN_FUNC_GPIO);
    handle = csi_gpio_pin_initialize(gpio_id, gpio_interrupt_handler);
    csi_gpio_pin_config_mode(handle, GPIO_MODE_PULLNONE);
    csi_gpio_pin_config_direction(handle, GPIO_DIRECTION_INPUT);
    csi_gpio_pin_set_irq(handle, GPIO_IRQ_MODE_RISING_EDGE, 1);

    while (int_flag);

    int_flag = 1;
    csi_gpio_pin_uninitialize(handle);
}

bool gpio_input_test(int gpio_id)
{
    gpio_pin_handle_t     handle;
    bool val = 0;

    drv_pinmux_config(gpio_id, PIN_FUNC_GPIO);
    handle = csi_gpio_pin_initialize(gpio_id, NULL);
    csi_gpio_pin_config_mode(handle, GPIO_MODE_PULLNONE);
    csi_gpio_pin_config_direction(handle, GPIO_DIRECTION_INPUT);
    csi_gpio_pin_read(handle, &val);
    csi_gpio_pin_uninitialize(handle);

    return val;
}

#if defined(APP_PWM_EN) && APP_PWM_EN
void pwm_test_start(int argc, char **argv)
{
    uint8_t  pwm_id   = atoi(argv[3]);
    uint8_t ch = 0;
    uint32_t duty = 0, period = 0;
    if(0 == pwm_id) {
        ch = PWM0_CH;
    } else {
        printf("pwm id %d incorrect!\n", pwm_id);
        return;
    }

    if (6 != argc) {
        printf("User doesn't config period/duty, use default: 3000/1500!\n ");
        period = 3000;
        duty   = 1500;
    } else {
        period = atoi(argv[4]);
        duty   = atoi(argv[5]);
        printf("User config period %d, duty %d\n", period, duty);
    }

    app_pwm_config(ch, period, duty);
    mdelay(20);
    app_pwm_start(ch);

    return;
}

void pwm_test_stop(int argc, char **argv)
{
    uint8_t  pwm_id   = atoi(argv[3]);
    uint8_t ch = 0;
    if(0 == pwm_id) {
        ch = PWM0_CH;
    } else {
        printf("pwm id %d incorrect!\n", pwm_id);
        return;
    }

    app_pwm_stop(ch);
    return;
}
#endif //APP_PWM_EN

static void cmd_app_func(char *wbuf, int wbuf_len, int argc, char **argv)
{
    int cmd_err = 0;
    if (argc < 3) {
        cmd_err = 1;
    }

    if (cmd_err == 0) {
        if (strcmp(argv[1], "set") == 0) {
            if (argc == 4) {
                gpio_output_test(atoi(argv[2]), atoi(argv[3]));
                printf("set gpio %d val=%d\n", atoi(argv[2]), atoi(argv[3]));
            } else {
                cmd_err = 1;
            }
        } else if (strcmp(argv[1], "get") == 0) {
            bool val = gpio_input_test(atoi(argv[2]));
            printf("get gpio %d val=%d\n", atoi(argv[2]), val);
        } else if (strcmp(argv[1], "irq") == 0) {
            gpio_interrupt_test(atoi(argv[2]));
            printf("gpio %d irq\n", atoi(argv[2]));
#if defined(APP_PWM_EN) && APP_PWM_EN
        } else if (strcmp(argv[1], "pwm") == 0) {
            if(argc < 4) {
                cmd_err = 1;
            } else {
                if (strcmp(argv[2], "start") == 0) {
                    pwm_test_start(argc, argv);
                } else if (strcmp(argv[2], "stop") == 0) {
                    pwm_test_stop(argc, argv);
                }
            }
        } else if (strcmp(argv[1], "led") == 0) {
            if(argc < 4) {
                cmd_err = 1;
            } else {
                if (strcmp(argv[2], "start") == 0) {
                    app_pwm_led_control(1);
                } else if (strcmp(argv[2], "stop") == 0) {
                    app_pwm_led_control(0);
                } else if (strcmp(argv[2], "set") == 0) {
                    int32_t bright = atoi(argv[3]);
                    app_pwm_led_set_brightness(bright);
                }
            }
#endif
        }
    }

    if (cmd_err) {
        printf("usage:\n");
        printf("\tgpio set pinid 0/1\n");
        printf("\tgpio get pinid\n");
        printf("\tgpio irq pinid\n");
        printf("\tgpio pwm start <pwm_id> <period> <duty>\n");
        printf("\tgpio pwm stop <pwm_id>\n");
        printf("\t\tpwm_id: 0/1\n");
        printf("\tgpio led start\n");
        printf("\tgpio led stop\n");
        printf("\tgpio led set <brightness>\n");
        printf("\t\tbrighness: 10 - 100\n");
#ifdef USER_GPIO_LIST_STR
        printf(USER_GPIO_LIST_STR);
#endif
    }
}

void cli_reg_cmd_gpio(void)
{
    static const struct cli_command cmd_info = {"gpio", "gpio output/input/irq", cmd_app_func};

    aos_cli_register_command(&cmd_info);
}
